﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Microsoft.Kinect;
using Microsoft.Win32;
using Kinect.Toolbox;
using Kinect.Toolbox.Gestures;
using Kinect.Toolbox.Voice;
using System.Threading;
using System.Threading.Tasks;
using Kinect.Toolbox.Record;
using Kinectver1._0.CadObject;

namespace Kinectver1._0
{
    //a listing is what we will use to represent joint information. 
    public class Listing
    {
        public DateTime Time { get; set; } //time of occurance
        public Vector3 Pos { get; set; } //x y z location
        public Ellipse DisplayEllipse { get; set; } //display ellipse
    }

    public abstract class gesture
    {

        public int minPeriod { get; set; } //
        //the collection of joints for this specific gesture
        public List<Listing> listings = new List<Listing>(); 
        //what teh gesture will return as a string to the main window
        public event Action<string> gestureDectected;
        //last time// set it now on init
        public DateTime lastGestureDate = DateTime.Now;
        //the ammount of listings to observer (your window of time)
        readonly int windowSize;

        //printing!
        public Canvas gesturesCanvas { get; set; } //for drawing
        public Color DisplayColor { get; set; }

        //constructor, assome its 20 listing as our window size
        protected gesture(int window = 20)
        {
            this.windowSize = window;
            minPeriod = 0;
            DisplayColor = Colors.Red;
        }

        //confusing, but this is our listings of listing... in a list..
        /*
        protected List<Listing> Listings
        {
            get { return listings; }
        }
         */


        //identifier from orogin of hand (eg. right, or left)
        public string hand
        {
            get;
            set;
        }
        
        public int WindowSize
        {
            get { return windowSize; }
        }

        public virtual void add(SkeletonPoint pos, KinectSensor sensor)
        {
            Listing newListing = new Listing { Pos = pos.ToVector3(), Time = DateTime.Now };
            listings.Add(newListing);

            //Draw to the canvas
            if (gesturesCanvas != null)
            {
                newListing.DisplayEllipse = new Ellipse
                {
                    Width = 4,
                    Height = 4,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Top,
                    StrokeThickness = 2.0,
                    Stroke = new SolidColorBrush(DisplayColor),
                    StrokeLineJoin = PenLineJoin.Round
                };

                Vector2 vector2 = Tools.Convert(sensor, pos);

                float x = (float)(vector2.X * gesturesCanvas.ActualWidth);
                float y = (float)(vector2.Y * gesturesCanvas.ActualHeight);

                Canvas.SetLeft(newListing.DisplayEllipse, x-newListing.DisplayEllipse.Width / 2);
                Canvas.SetTop(newListing.DisplayEllipse, y - newListing.DisplayEllipse.Height / 2);

                gesturesCanvas.Children.Add(newListing.DisplayEllipse);

            }

            //clean upp
            if (listings.Count > windowSize)
            {
                Listing listingToRemove = listings[0];

                if (gesturesCanvas != null)
                {
                    gesturesCanvas.Children.Remove(listingToRemove.DisplayEllipse);
                }

                listings.Remove(listingToRemove);
            }

            LookForGestures();
        }

        protected abstract void LookForGestures();

        protected void gestureIsDetected(string gestureType)
        {
            //Too Close?
            if (DateTime.Now.Subtract(lastGestureDate).TotalMilliseconds > minPeriod)
            {
                if (gestureDectected != null)
                    gestureDectected(gestureType);
                lastGestureDate = DateTime.Now;
            }
            listings.ForEach(e =>
            {
                if (gesturesCanvas != null)
                    gesturesCanvas.Children.Remove(e.DisplayEllipse);
            });
            listings.Clear();
            

        }
    }

    //this class observes to see if your right hand begins teh operation for the two hand start
    public class rightHandObserver : gesture
    {
        public float rightHandMinimalLength { get; set; }
        public float rightHandMaximalHeight { get; set; }
        public int rightHandMinDuration { get; set; }
        public int rightHandMaxDuration { get; set; }


        public rightHandObserver(int period = 20)
            : base(period)
        {
            rightHandMinimalLength = 0.4f;
            rightHandMaximalHeight = 0.2f;
            rightHandMinDuration = 200;
            rightHandMaxDuration = 1500;
            hand = "right";
        }

        // for swiping, i feel like i will ue this again later
        protected bool ScanPositions(Func<Vector3, Vector3, bool> heightFunction, Func<Vector3, Vector3, bool> directionFunction,
            Func<Vector3, Vector3, bool> lengthFunction, int minTime, int maxTime)
        {
            int start = 0;

            for (int i = 1; i < listings.Count - 1; i++)
            {
                if (!heightFunction(listings[0].Pos, listings[i].Pos) || !directionFunction(listings[i].Pos, listings[i + 1].Pos))
                {
                    start = i;
                }
                if (lengthFunction(listings[i].Pos, listings[start].Pos))
                {
                    double totalMilliseconds = (listings[i].Time - listings[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime && totalMilliseconds <= maxTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        //you are looking for grabing?/and resize
        //but most of all, we are going to see if two hand gesture start occurs.. 
        protected override void LookForGestures()
        {
            // Swipe to right
            if (ScanPositions((p1, p2) => Math.Abs(p2.Y - p1.Y) < rightHandMaximalHeight, // Height
                (p1, p2) => p2.X - p1.X < 0.01f, // Progression to left , end point, minus the other point is still greater
                (p1, p2) => Math.Abs(p2.X - p1.X) > rightHandMinimalLength, // Length
                rightHandMinDuration, rightHandMaxDuration)) // Duration
            {
                gestureIsDetected("SwipeToLeft");
                return;
            }
        }
    }

    //this class observes to see if your left hand begins teh operation for the two hand start
    public class leftHandObserver : gesture
    {
        public float leftHandMinimalLength { get; set; }
        public float leftHandMaximalHeight { get; set; }
        public int leftHandMinDuration { get; set; }
        public int leftHandMaxDuration { get; set; }


        public leftHandObserver(int period = 20)
            : base(period)
        {
            leftHandMinimalLength = 0.4f;
            leftHandMaximalHeight = 0.2f;
            leftHandMinDuration = 250;
            leftHandMaxDuration = 1500;
            hand = "left";
        }

        // for swiping, i feel like i will ue this again later
        protected bool ScanPositions(Func<Vector3, Vector3, bool> heightFunction, Func<Vector3, Vector3, bool> directionFunction,
            Func<Vector3, Vector3, bool> lengthFunction, int minTime, int maxTime)
        {
            int start = 0;

            for (int i = 1; i < listings.Count - 1; i++)
            {
                if (!heightFunction(listings[0].Pos, listings[i].Pos) || !directionFunction(listings[i].Pos, listings[i + 1].Pos))
                {
                    start = i;
                }

                if (lengthFunction(listings[i].Pos, listings[start].Pos))
                {
                    double totalMilliseconds = (listings[i].Time - listings[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime && totalMilliseconds <= maxTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        protected override void LookForGestures()
        {
            // Swipe to right
            if (ScanPositions((p1, p2) => Math.Abs(p2.Y - p1.Y) < leftHandMaximalHeight, // Height
                (p1, p2) => p2.X - p1.X > -0.01f, // Progression to right
                (p1, p2) => Math.Abs(p2.X - p1.X) > leftHandMinimalLength, // Length
                leftHandMinDuration, leftHandMaxDuration)) // Duration
            {
                gestureIsDetected("SwipeToRight");
                return;
            }
        }
    }
};